package com.zhangmeng.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.BufferUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import cn.hutool.log.StaticLog;
import cn.hutool.socket.aio.AioServer;
import cn.hutool.socket.aio.AioSession;
import cn.hutool.socket.aio.SimpleIoAction;
import com.zhangmeng.callBack.DoConnectionBegin;
import com.zhangmeng.callBack.DoConnectionLost;
import com.zhangmeng.callBack.HandlerApiCallBack;
import com.zhangmeng.handler.ClientHandler;
import com.zhangmeng.service.*;
import com.zhangmeng.utils.Globalobj;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;



/**
 * @author zm
 * @date 2025/2/21 15:04
 * @version: 1.0
 */
public class ServerImpl implements Server {

    private final Log log = LogFactory.get();

    private Config config;

    private ServerSocket serverSocket;

    private BufferedReader in;

    //private Router router; //当前Server由用户绑定的回调router,也就是Server注册的链接对应的处理业务
    private MsgHandle msgHandle; //当前Server的消息管理模块，用来绑定MsgId和对应的处理方法

    public static Map<String, Socket> socketList = new HashMap<>();

    //该Server的连接创建时Hook函数
    public DoConnectionBegin OnConnStart;
    //该Server的连接断开时的Hook函数
    public DoConnectionLost OnConnStop;

    //当前Server的链接管理器
    private ConnManager ConnMgr;

    @Override
    public void Start() {
        log.info("[START] Server listenner at Name: {}, IPVersion {}, is starting", config.getName(), config.getIPVersion());
        log.info("[START] Server listenner at IP: {}, Port {}, is starting", config.getIP(), config.getPort());
        try {
            serverSocket = new ServerSocket(config.getPort());

            int cid = 0;

            while (true) {
                Socket accept = serverSocket.accept();
                String key = accept.getInetAddress().getHostAddress() + ":" + accept.getPort();
                socketList.put(key, accept);
                log.info("key=====================================: " + key);
                //new ClientHandler(accept).start();
                log.info("[ACCEPT] Accept a client at IP: {}, Port {}", accept.getInetAddress().getHostAddress(), accept.getPort());

                //3.2 设置服务器最大连接控制,如果超过最大连接，那么则关闭此新的连接
                if (this.ConnMgr.Len() >= Globalobj.getInstance().getMaxConn()) {
                    accept.close();
                    log.info("[ACCEPT] The number of connections exceeds the maximum limit, close the new connection");
                    continue;
                }


                Connection conn = new ConnectionImpl(this,accept, cid, this.msgHandle);
                conn.Start();
                cid++;
            }

        } catch (IOException e) {
//            throw new RuntimeException(e);
            log.error(e.getMessage());
        }
    }

    @Override
    public void Stop() {
        log.info("[STOP] Server listenner at IP: {}, Port {}, is stoped", config.getIP(), config.getPort());
        //将其他需要清理的连接信息或者其他信息 也要一并停止或者清理
        this.ConnMgr.ClearConn();
        try {
            serverSocket.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void SetOnConnStart(DoConnectionBegin onConnStart) {
        this.OnConnStart = onConnStart;
    }

    @Override
    public void SetOnConnStop(DoConnectionLost onConnStop) {
        this.OnConnStop = onConnStop;
    }

    @Override
    public void CallOnConnStart(Connection connection) {
        if (this.OnConnStart != null) {
            log.info("[ONCONNSTART] Call OnConnStart");
            this.OnConnStart.run(connection);
        }
    }

    @Override
    public void CallOnConnStop(Connection connection) {
        if (this.OnConnStop != null){
            log.info("[ONCONNSTOP] Call OnConnStop");
            this.OnConnStop.run(connection);
        }
    }

    @Override
    public void Serve() {

    }

    @Override
    public void AddRouter(int msgId, Router router) {
        this.msgHandle.AddRouter(msgId, router);
        log.info("[ADD ROUTER] Add a router to server");
    }

    @Override
    public ConnManager GetConnMgr() {
        return this.ConnMgr;
    }

    public void setConfig(Config config) {
        this.config = config;
    }

    public static class Config {
        //服务器的名称
        private String Name;

        //tcp4 or other
        private String IPVersion;

        //服务绑定的IP地址
        private String IP;
        //服务绑定的端口
        private int Port;

        public String getName() {
            return Name;
        }

        public void setName(String name) {
            Name = name;
        }

        public String getIPVersion() {
            return IPVersion;
        }

        public void setIPVersion(String IPVersion) {
            this.IPVersion = IPVersion;
        }

        public String getIP() {
            return IP;
        }

        public void setIP(String IP) {
            this.IP = IP;
        }

        public int getPort() {
            return Port;
        }

        public void setPort(int port) {
            Port = port;
        }
    }

//    public Router getRouter() {
//        return router;
//    }
//
//    public void setRouter(Router router) {
//        this.router = router;
//    }


    public MsgHandle getMsgHandle() {
        return msgHandle;
    }

    public void setMsgHandle(MsgHandle msgHandle) {
        this.msgHandle = msgHandle;
    }

    public DoConnectionBegin getOnConnStart() {
        return OnConnStart;
    }

    public void setOnConnStart(DoConnectionBegin onConnStart) {
        OnConnStart = onConnStart;
    }

    public DoConnectionLost getOnConnStop() {
        return OnConnStop;
    }

    public void setOnConnStop(DoConnectionLost onConnStop) {
        OnConnStop = onConnStop;
    }

    public ConnManager getConnMgr() {
        return ConnMgr;
    }

    public void setConnMgr(ConnManager connMgr) {
        ConnMgr = connMgr;
    }
}
